package com.part2.dao.common;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.part2.common.query.Page;

public class BaseDaoImpl<T, ID extends Serializable> extends
		HibernateDaoSupport implements BaseDao<T, ID> {

	private static final Log logger = LogFactory.getLog(BaseDaoImpl.class);

	public void save(T entity) {
		try {
			getHibernateTemplate().save(entity);
		} catch (RuntimeException e) {
			logger.error(entity.getClass().getName(), e);
		}
	}

	public void delete(T entity) {
		try {
			getHibernateTemplate().delete(entity);
		} catch (RuntimeException e) {
			logger.error(entity.getClass().getName(), e);
		}
	}

	public List<T> findAll(Class<T> entityClass) {
		try {
			return getHibernateTemplate().find("from " + entityClass.getName());
		} catch (RuntimeException e) {
			logger.error(entityClass.getName(), e);
			return new ArrayList<T>();
		}
	}

	public void saveOrUpdate(T entity) {
		try {
			getHibernateTemplate().saveOrUpdate(entity);
		} catch (RuntimeException e) {
			logger.error(entity.getClass().getName(), e);
		}
	}

	public T findById(Class<T> entityClass, ID id) {
		try {
			return (T) getHibernateTemplate().get(entityClass, id);
		} catch (RuntimeException e) {
			logger.error(entityClass.getName(), e);
			return null;
		}
	}

	public List<Object> find(String hql, Object... values) {
		try {
			return getHibernateTemplate().find(hql, values);
		} catch (RuntimeException e) {
			logger.error(hql, e);
			return null;
		}
	}

	public Object findUnique(final String hql, final Object... values) {
		try {
			return getHibernateTemplate().execute(new HibernateCallback() {
				public Object doInHibernate(Session s)
						throws HibernateException, SQLException {
					Query query = createQuery(s, hql, values);
					return query.uniqueResult();
				}
			});
		} catch (RuntimeException e) {
			logger.error(hql, e);
			return null;
		}
	}

	public int findInt(final String hql, final Object... values) {
		int i = 0;
		Object o = findUnique(hql, values);
		if (o != null) {
			try {
				i = Integer.parseInt(o.toString());
			} catch (Exception e) {
				logger.error(e);
				i = 0;
			}
		}
		return i;
	}

	public int findTotalCount(Class<T> entityClass, final String where,
			final Object... values) {
		String hql = "select count(e) from " + entityClass.getName() + " as e "
				+ where;
		return findInt(hql, values);
	}

	public int findTotalCount(Class<T> entityClass) {
		return findTotalCount(entityClass, "");
	}

	public List<T> findByProperty(Class<T> entityClass, String propertyName,
			Object value) {
		try {
			String queryStr = "from " + entityClass.getName()
					+ " as model where model." + propertyName + "=?";
			return getHibernateTemplate().find(queryStr, value);
		} catch (RuntimeException e) {
			logger.error(propertyName, e);
			return null;
		}
	}

	public List<T> findByExample(T entity) {
		try {
			List<T> results = getHibernateTemplate().findByExample(entity);
			return results;
		} catch (RuntimeException re) {
			logger.error(re);
			return null;
		}
	}

	public T merge(T entity) {
		try {
			T result = (T) getHibernateTemplate().merge(entity);
			return result;
		} catch (RuntimeException re) {
			logger.error(re);
			return null;
		}
	}

	public void attachClean(T entity) {
		try {
			getHibernateTemplate().lock(entity, LockMode.NONE);
		} catch (RuntimeException re) {
			logger.error(re);
		}
	}

	public Page<T> findByPage(final Page<T> page, final String hql,
			final Object... values) {
		try {
			return (Page<T>) getHibernateTemplate().execute(
					new HibernateCallback() {
						public Object doInHibernate(Session s)
								throws HibernateException, SQLException {
							Query query = createQuery(s, hql, values);
							if (page.isFirstSetted()) {
								query.setFirstResult(page.getFirst());
							}
							if (page.isPageSizeSetted()) {
								query.setMaxResults(page.getPageSize());
							}
							page.setResult(query.list());
							return page;
						}
					});
		} catch (RuntimeException e) {
			logger.error(hql, e);
			return null;
		}
	}

	public Query createQuery(Session session, String hql, Object... objects) {
		Query query = session.createQuery(hql);
		query.setCacheable(true);
		if (objects != null) {
			for (int i = 0; i < objects.length; i++) {
				query.setParameter(i, objects[i]);
			}
		}
		return query;
	}

}